using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using Shaders.Classes;
using Shaders.Classes.Components;
using Shaders.Classes.GameObjects;
using JigLibX.Physics;
using JigLibX.Geometry;
using JigLibX.Collision;

namespace Shaders
{

    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
       
        GraphicsDeviceManager graphics;
        Tank testTank;
        Camera mainCamera;
        Skybox skybox;
        SpriteBatch spriteBatch;
        Vector4 lightPosition;
        KeyboardState keyboardState;
        KeyboardState previousKeyboardState;

        Terrain terrain;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            // Create the cursor component.
            
            graphics.IsFullScreen = false;
            graphics.PreferredBackBufferHeight = 1024;
            graphics.PreferredBackBufferWidth = 1280;
        }

        

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>

        protected override void Initialize()
        {
            graphics.SynchronizeWithVerticalRetrace = false;
            this.IsFixedTimeStep = false;
            GraphicsDevice.RenderState.MultiSampleAntiAlias = true;
            
            lightPosition = new Vector4(0.0f, 10.0f, 10.0f, 1.0f);
            mainCamera = new Camera(GraphicsDevice);
            mainCamera.Initialize(graphics.GraphicsDevice.Viewport.AspectRatio);
            mainCamera.Position = new Vector3(208.0f, 70.0f, -352.0f);
            mainCamera.Angle = new Vector3(0.4f, -3.6f, 0.0f);

            testTank = new Tank(GraphicsDevice, "p1_wedge", "specular", new Vector3(250.0f, 40.0f, -250.0f), 0.0f, new Vector4(0.0f, 0.0f, 0.0f, 1.0f), 0.005f);

            GraphicsDevice.RenderState.FillMode = FillMode.Solid;
            skybox = new Skybox(Content);
            skybox.Initialize(graphics.GraphicsDevice);
            spriteBatch = new SpriteBatch(GraphicsDevice);

            graphics.ApplyChanges();
            
            base.Initialize();
        }

        
        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {   
            mainCamera.LoadContent(Content);

            testTank.LoadContent(Content);
            Texture2D heightMap = Content.Load<Texture2D>("Textures\\heightmap");
            terrain = new Terrain( Content.Load<Effect>("Shaders\\Series4Effects"));


            terrain.LoadContent(heightMap, GraphicsDevice, Content);
        }

        static void Main(string[] args)
        {
            using (Game1 game = new Game1())
            {
                game.Run();
            }
        }


        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>

        protected override void UnloadContent()
        {
            
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            keyboardState = Keyboard.GetState();
            
            if (keyboardState.IsKeyDown(Keys.Escape))
            {
                this.Exit();
            }

            if(keyboardState.IsKeyDown(Keys.T) && previousKeyboardState.IsKeyUp(Keys.T))
            {
                terrain.ToggleWalkMatrix();
            }

            previousKeyboardState = keyboardState;

            mainCamera.Update(GraphicsDevice.Viewport.Width, gameTime);


            terrain.Update(mainCamera, gameTime);

            testTank.Update(gameTime, mainCamera, new Vector4(-1.0f, 0.0f, -1.0f, 1.0f));
            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        /// 

        protected override void Draw(GameTime gameTime)
        {

            GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Aquamarine, 1.0f, 0);

            skybox.Draw(GraphicsDevice, mainCamera.Position, mainCamera.View * mainCamera.Projection);
            //ship2.Draw(gameTime, GraphicsDevice, mainCamera);
            //ship.Draw(gameTime, GraphicsDevice, mainCamera);
            
            terrain.DrawTerrain(mainCamera, gameTime);

            testTank.Draw(gameTime, GraphicsDevice, mainCamera);
            
            mainCamera.Draw(gameTime, GraphicsDevice, mainCamera, spriteBatch);

            
            base.Draw(gameTime);
        }
    }
}